#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <iostream>
#include <pthread.h>
#include "Server.h"
#include "../modelo/Personaje.h"
#include "../constantes.h"
#include "../modelo/TipoEntidad.h"
#include "../modelo/util/LoggerConsola.h"
#include "../modelo/mision/MotorMision.h"
#include "MotorServer.h"

using namespace std;

#define cantMinimaJugadores 1

void cargarBonus(Escenario* escenario);

void cargarBonus(Escenario* unEscenario){
	Bonus* bonusVelocidad = new BonusVelocidad();
	Bonus* bonusVida = new BonusVida();
	Bonus* bonusMagia = new BonusMagia();
	Bonus* bonusMapa = new BonusMapa();
	Bonus* bonusLampara = new BonusLampara();
//	Bonus* bonusBomba = new BonusBomba();
//	Bonus* bonusGolem = new BonusGolem();
	Bonus* bonusHielo = new BonusHielo();
	unEscenario->getCasilla(0,3)->agregarBonus(bonusVelocidad);
	unEscenario->getCasilla(30,10)->agregarBonus(bonusVida);
	unEscenario->getCasilla(40,25)->agregarBonus(bonusMagia);
	unEscenario->getCasilla(15,29)->agregarBonus(bonusMapa);
	unEscenario->getCasilla(5,39)->agregarBonus(bonusLampara);
//	unEscenario->getCasilla(1,5)->agregarBonus(bonusBomba);
//	unEscenario->getCasilla(0,7)->agregarBonus(bonusGolem);
	unEscenario->getCasilla(40,20)->agregarBonus(bonusHielo);
	unEscenario->agregarBonus(bonusVelocidad);
	unEscenario->agregarBonus(bonusVida);
	unEscenario->agregarBonus(bonusMagia);
	unEscenario->agregarBonus(bonusMapa);
	unEscenario->agregarBonus(bonusLampara);
	//unEscenario->agregarBonus(bonusBomba);
	//unEscenario->agregarBonus(bonusGolem);
	unEscenario->agregarBonus(bonusHielo);



}
// Corre el servidor. Va aceptando y agregando conexiones, y cerrando
// aquellas que ya no esta trabajando.

void Server::run() {
	this->chatRecibir = new ChatRecibirServer(puertoChatRecv, this);
	this->chatRecibir->start();
	this->chatEnviar = new ChatEnviarServer(this);
	this->chatEnviar->start();
	int newsockfd = -1;
	int newsockfdchat = -1;
	string nombrePersonajeChat;
	Mutex* escenarioMutex = new Mutex();
	cargarBonus(this->juego->getEscenario());
	MotorMision motorMision(this, nombreEscenario);
	motorMision.start();

	MotorServer motorServer(this, nombreEscenario);
	motorServer.start();
	cout << "trabajando inicial: " << trabajando << endl;
	while (trabajando) {
		cout << "SERVER ESPERANDO CONEXION";
		newsockfd = aSocket.acceptConnection();
		newsockfdchat = chatSocket.acceptConnection();
		cout << "SERVER CONEXION ESTABLECIDA" << endl;
		if (newsockfdchat > 0 && isWorking()) {
			cout << "SE GENERA UNA NUEVA CONEXION EN EL CHAT" << endl;
			Connection* conn = new Connection(newsockfdchat);
			nombrePersonajeChat = conn->recvData();
			cout << "NUEVO JUGADOR EN EL CHAT: " << nombrePersonajeChat << endl;
			jugadoresSockets.insert(
					pair<string, Connection*>(nombrePersonajeChat, conn));
			cout << "CANTIDAD DE SOCKETS DE CHAT: " << jugadoresSockets.size()
					<< endl;
		}
		if (newsockfd > 0 && isWorking()) {
			cout << "SE GENERA UNA NUEVA CONEXION EN EL SERVER" << endl;
			Connection *connection = new Connection(newsockfd, this->juego,
					connections.size(), this, escenarioMutex);
			clearConnections();
			connMutex.lock();
			connections.push_back(connection);
			connection->start();
			connectionCount++;
			cout << "CANTIDAD DE CONNECTIONS SERVER: " << connections.size()
					<< endl;
			connMutex.unLock();
		}

		cout << "llega aca abajo y trabajando es: " << trabajando << endl;
		newsockfd = 0;
		newsockfdchat = 0;
	}
	delete escenarioMutex;
	shutdownConnections();
	delete (this->chatRecibir);
	delete (this->chatEnviar);
	cout << "TERMINO SERVER: " << endl;
}

bool Server::isWorking() {
	workingMutex.lock();
	bool aux = working;
	workingMutex.unLock();
	return aux;
}

void Server::setWorking(bool working) {
	workingMutex.lock();
	this->working = working;
	workingMutex.unLock();
}

void Server::clearConnections() {
	connMutex.lock();
	list<Connection*>::iterator it;
	if (connections.size() > 0) {
		it = connections.begin();
		while (connections.size() > 0 && it != connections.end()) {
			Connection *c = *it;
			if (!c->isWorking()) {
				c->connectionShutdown();
				c->join();
				it = connections.erase(it);
				delete c;
			} else {
				it++;
			}
		}
	}
	connMutex.unLock();
}

void Server::serverShutdown() {
	connMutex.lock();
	setWorking(false);
	aSocket.shutdownSocket();
	chatSocket.shutdownSocket();

	connMutex.unLock();
}

void Server::shutdownConnections() {
	list<Connection*>::iterator it;
	for (it = connections.begin(); it != connections.end(); it++) {
		Connection *c = *it;
		c->connectionShutdown();
		c->join();
		delete c;
	}
}

string Server::getNombreEscenario() {
	return this->nombreEscenario;
}

list<Connection*> Server::getConnections() {
	return this->connections;
}

list<Personaje*> Server::getPersonajesInactivos() {
	return this->personajesInactivos;
}

Escenario* Server::getEscenario() {
	return this->juego->getEscenario();
}

Builder* Server::getBuilderJuego() {
	return this->builderJuego;
}

void Server::agregarInactivo(Personaje* personaje) {
	this->personajesInactivos.push_back(personaje);
}

void Server::borrarPersonajeInactivo(Personaje* personaje) {
	this->personajesInactivos.remove(personaje);
}

map<string, set<string>*> Server::getMapPersonajePosiciones() {
	return this->mapPersonajePosiciones;
}

void Server::setMapPersonajePosiciones(map<string, set<string>*> map) {
	this->mapPersonajePosiciones = map;
}

void Server::agregarPosicionesVisitadas(string nombrePersonaje,
		set<string>* posicionesVisitadas) {
	this->mapPersonajePosiciones[nombrePersonaje] = posicionesVisitadas;
}

queue<string>* Server::getMensajesChat() {
	return &this->mensajesChat;
}
map<string, Connection*> Server::getJugadoresSockets() {
	return this->jugadoresSockets;
}

void Server::borrarJugadorDeSockets(string nombre) {
	this->jugadoresSockets.erase(nombre);
}

void Server::setTrabajando(bool b){
	this->trabajando = false;
}

bool Server::getTrabajando(){
	return this->trabajando;
}
